#![allow(unused_variables, unused_mut)]

use std::any::Any;

use crate::view::Cx;
use crate::widget::ChangeFlags;
use crate::{id::Id, message::EventResult, view::View, widget::Pod};

pub trait ViewSequence<T, A = ()> {
    type State;

    fn build(&self, cx: &mut Cx, pods: &mut Vec<Pod>) -> Self::State;

    fn rebuild(
        &self,
        prev: &Self,
        cx: &mut Cx,
        state: &mut Self::State,
        elements: &mut PodSlice,
    ) -> ChangeFlags;

    fn message(
        &self,
        id_path: &[Id],
        event: Box<dyn Any>,
        state: &mut Self::State,
        app_state: &mut T,
    ) -> EventResult<A>;

    fn count(&self, state: &mut Self::State) -> usize;
}

pub trait ViewMarker {}

pub struct PodSlice<'a> {
    pub(crate) elements: &'a mut [Pod],
    pub(crate) current: usize,
}

impl<'a> PodSlice<'a> {
    pub fn new(els: &'a mut [Pod]) -> Self {
        PodSlice {
            elements: els,
            current: 0,
        }
    }

    pub fn mutate(&mut self) -> &mut Pod {
        self.current += 1;
        &mut self.elements[self.current - 1]
    }
}

macro_rules! impl_view_sequence_tuple {
    ($($V:ident),* ; $($n:tt),*) => {
        impl<T, A, $( $V : ViewSequence<T, A>, )*> ViewSequence<T, A> for ( $($V ,)* ) {
            type State = ( $( $V::State, )* );

            fn build(&self, cx: &mut Cx, pods: &mut Vec<Pod>) -> Self::State {
                ($( self.$n.build(cx, pods), )*)
            }

            fn rebuild(
                &self,
                prev: &Self,
                cx: &mut Cx,
                state: &mut Self::State,
                elements: &mut PodSlice,
            ) -> ChangeFlags {
                let mut ans = ChangeFlags::empty();
                $(let changed = self.$n.rebuild(&prev.$n, cx, &mut state.$n, elements);
                    ans |= changed;)*
                ans
            }

            fn message(
                &self,
                id_path: &[Id],
                event: Box<dyn Any>,
                state: &mut Self::State,
                app_state: &mut T,
            ) -> EventResult<A> {
                EventResult::Stale(event)
                    $(.or(|event| self.$n.message(id_path, event, &mut state.$n, app_state)))*
            }

            fn count(&self, state: &mut Self::State) -> usize {
                0 $( + self.$n.count(&mut state.$n))*
            }
        }
    };
}

impl_view_sequence_tuple!(;);
impl_view_sequence_tuple!(V0; 0);
impl_view_sequence_tuple!(V0, V1; 0, 1);
impl_view_sequence_tuple!(V0, V1, V2; 0, 1, 2);
impl_view_sequence_tuple!(V0, V1, V2, V3; 0, 1, 2, 3);
impl_view_sequence_tuple!(V0, V1, V2, V3, V4; 0, 1, 2, 3, 4);
impl_view_sequence_tuple!(V0, V1, V2, V3, V4, V5; 0, 1, 2, 3, 4, 5);
impl_view_sequence_tuple!(V0, V1, V2, V3, V4, V5, V6; 0, 1, 2, 3, 4, 5, 6);
impl_view_sequence_tuple!(V0, V1, V2, V3, V4, V5, V6, V7; 0, 1, 2, 3, 4, 5, 6, 7);
impl_view_sequence_tuple!(V0, V1, V2, V3, V4, V5, V6, V7, V8; 0, 1, 2, 3, 4, 5, 6, 7, 8);

impl<T, A, VS: ViewSequence<T, A>> ViewSequence<T, A> for Vec<VS> {
    type State = Vec<VS::State>;

    fn build(&self, cx: &mut Cx, pods: &mut Vec<Pod>) -> Self::State {
        self.iter().map(|v| v.build(cx, pods)).collect()
    }

    fn rebuild(
        &self,
        prev: &Self,
        cx: &mut Cx,
        state: &mut Self::State,
        elements: &mut PodSlice,
    ) -> ChangeFlags {
        self.iter()
            .zip(prev)
            .zip(state)
            .fold(ChangeFlags::empty(), |flags, ((v, p), s)| {
                flags | v.rebuild(p, cx, s, elements)
            })
    }

    fn message(
        &self,
        id_path: &[Id],
        event: Box<dyn Any>,
        state: &mut Self::State,
        app_state: &mut T,
    ) -> EventResult<A> {
        self.iter()
            .zip(state)
            .fold(EventResult::Stale(event), |acc, (v, s)| {
                acc.or(|e| v.message(id_path, e, s, app_state))
            })
    }

    fn count(&self, state: &mut Self::State) -> usize {
        self.iter().zip(state).map(|(v, s)| v.count(s)).sum()
    }
}

impl<T, A, VT: View<T, A> + ViewMarker> ViewSequence<T, A> for VT
where
    VT::Element: 'static,
{
    type State = (Id, VT::State);

    fn build(&self, cx: &mut Cx, pods: &mut Vec<Pod>) -> Self::State {
        let (id, state, el) = self.build(cx);
        pods.push(Pod::new(el));
        (id, state)
    }

    fn rebuild(
        &self,
        prev: &Self,
        cx: &mut Cx,
        state: &mut Self::State,
        elements: &mut PodSlice,
    ) -> ChangeFlags {
        let pod = elements.mutate();
        let el = pod.widget.as_any_mut().downcast_mut().unwrap();
        <VT as View<T, A>>::rebuild(self, prev, cx, &mut state.0, &mut state.1, el)
    }

    fn message(
        &self,
        id_path: &[Id],
        event: Box<dyn Any>,
        state: &mut Self::State,
        app_state: &mut T,
    ) -> EventResult<A> {
        if let Some((first, other)) = id_path.split_first() {
            if first == &state.0 {
                return <VT as View<T, A>>::message(self, other, &mut state.1, event, app_state);
            }
        }
        EventResult::Stale(event)
    }

    fn count(&self, _state: &mut Self::State) -> usize {
        1
    }
}
